<?php

require_once 'common_engine.php';

class EditableDataReaderStub implements IDataset
{
    const ReadingMode = 0;
    const InsertMode = 1;
    const EditMode = 2;

    private $dataArray;
    private $opened;
    private $index;

    /** @var array */
    private $conditions;

    /** @var string[] */
    private $primaryKeyFieldNames;

    /** @var int */
    private $mode;
    private $valuesToInsert;
    private $valuesToEdit;

    private function CheckOpened()
    {
        if (!$this->IsOpened())
            throw new Exception('DataReader is not opened');
    }

    private function IsOpened()
    {
        return $this->index >= -1;
    }

    /**
     * @return boolean
     */
    private function CheckCurrentRecordForConditions()
    {
        foreach($this->conditions as $condition)
        {
            $fieldName = $condition['fieldName'];
            $value = $condition['value'];

            if ($this->GetFieldValueByName($fieldName) != $value)
                return false;
        }
        return true;
    }

    /**
     * @param array $dataArray
     * @param string[] $primaryKeyFieldNames
     */
    public function __construct($dataArray, $primaryKeyFieldNames = null)
    {
        $this->dataArray = $dataArray;
        $this->index = -2;
        $this->opened = false;
        $this->primaryKeyFieldNames = $primaryKeyFieldNames ? $primaryKeyFieldNames : array();
        $this->conditions = array();
        $this->mode = EditableDataReaderStub::ReadingMode;

        $this->valuesToInsert = array();
    }

    public function __destruct()
    {
    }

    public function Open()
    {
        $this->opened = true;
        $this->index = -1;
    }

    public function Close()
    {
        $this->opened = false;
        $this->index = -2;
    }

    public function GetFieldValueByName($fieldName)
    {
        if ($this->mode == EditableDataReaderStub::InsertMode)
            return $this->valuesToInsert[$fieldName];
        elseif ($this->mode == EditableDataReaderStub::EditMode)
            return $this->valuesToEdit[$fieldName];
        else
            return $this->dataArray[$this->index][$fieldName];
    }

    public function Next()
    {
        $this->CheckOpened();
        
        $this->index++;
        while (($this->index < count($this->dataArray)) && !$this->CheckCurrentRecordForConditions())
            $this->index++;
        
        return ($this->index < count($this->dataArray));
    }

    /**
     * @param string $fieldName
     * @param mixed $value
     * @return void
     */
    public function SetFieldValueByName($fieldName, $value)
    {
        if ($this->mode == EditableDataReaderStub::InsertMode)
        {
            $this->valuesToInsert[$fieldName] = $value;
        }
        elseif ($this->mode == EditableDataReaderStub::EditMode)
        {
            $this->valuesToEdit[$fieldName] = $value;
        }
    }

    /**
     * @param string $fieldName
     * @param string $fileName
     * @return void
     */
    public function SetFieldValueByNameAsFileName($fieldName, $fileName)
    {
    }

    public function IsPrimaryKeyField($fieldName)
    {
        return in_array($fieldName, $this->primaryKeyFieldNames);
    }

    public function GetFieldNames()
    {
        if (count($this->dataArray) > 0)
        {
            return array_keys($this->dataArray[0]);
        }
        else
            return array();
    }

    /**
     * @return void
     */
    public function Edit()
    {
        $this->valuesToEdit = $this->dataArray[$this->index];
        $this->mode = EditableDataReaderStub::EditMode;
    }

    /**
     * @return void
     */
    public function Insert()
    {
        $this->mode = EditableDataReaderStub::InsertMode;
    }


    private function array_insert(&$array, $insert, $position)
    {
        settype($array, "array");
        settype($insert, "array");
        settype($position, "int");

        //if pos is start, just merge them
        if($position==0)
        {
            $array = array_merge($insert, $array);
        }
        else
        {
            //if pos is end just merge them
            if($position >= (count($array)-1)) {
                $array = array_merge($array, $insert);
            } else {
                //split into head and tail, then merge head+inserted bit+tail
                $head = array_slice($array, 0, $position);
                $tail = array_slice($array, $position);
                $array = array_merge($head, $insert, $tail);
            }
        }
    }
    /**
     * @return void
     */
    public function Post()
    {

        if ($this->mode == EditableDataReaderStub::InsertMode)
        {
            $this->array_insert($this->dataArray, array($this->valuesToInsert), $this->index + 1);
            $this->valuesToInsert = array();
            $this->Next();
        }
        elseif ($this->mode == EditableDataReaderStub::EditMode)
        {
            $this->dataArray[$this->index] = $this->valuesToEdit;
            $this->valuesToEdit = array();
        }
        $this->mode = EditableDataReaderStub::ReadingMode;
    }

    public function AddSimpleCondition($fieldName, ConditionOperator $operator, $value)
    {
        $this->conditions[] = array(
            'fieldName' => $fieldName,
            'value' => $value
        );
    }

    public function SaveToFile($fileName)
    {
        file_put_contents($fileName . '_data.txt', serialize($this->dataArray));
        if (isset($this->primaryKeyFieldNames))
            file_put_contents($fileName . '_keys.txt', serialize($this->primaryKeyFieldNames));
    }

    public static function CreateFromFile($fileName)
    {
        $dataArray = unserialize(file_get_contents($fileName . '_data.txt'));
        $primaryKeyFieldNames = null;
        if (file_exists($fileName . '_keys.txt'))
            $primaryKeyFieldNames = unserialize(file_get_contents($fileName . '_keys.txt'));
        return new EditableDataReaderStub($dataArray, $primaryKeyFieldNames);
    }
}

?>